#pragma once
#ifndef _WRD_DATA_H__
#define _WRD_DATA_H__

#include <string.h>
#include <stdlib.h>
#include <stdbool.h>

/*-----------------------------------------------------------------*\
    定义数据结构示例
\*-----------------------------------------------------------------*/

#ifdef __WRD_DATA_STRUCT_DEFINE__
#include "cstr.h"
typedef struct stack_cstr_s{  // 结构体容器主要用于存放指针数组
    cstr_t **start, **end;
    cstr_t **top;  // 指向待写入数据空间
} stack_cstr_t;

typedef struct queue_cstr_s{
    cstr_t **start, **end;
    cstr_t **head, **tail;
} queue_cstr_t;

#define debug_stack(stack_cstr) \
    cstr_t **ppoint = stack_cstr.start; \
    while(ppoint != stack_cstr.top){ \
        debug_cstr(**(ppoint++)); }}

#define debug_queue(queue_cstr) \
    cstr_t **ppoint = queue_cstr.head; \
    while(ppoint != queue_cstr.tail){ \
        debug_cstr(**(ppoint++)); }}
#endif  // __WRD_DATA_STRUCT_DEFINE__

/*
 * Stack management
 */

bool macro_stack_extend(void **start, void **top, void **end);

bool macro_queue_extend(void **start, void **head, void **tail, void **end);

#define STACK_ALLOC(stack,size)                                                 \
    (((stack).start = calloc((size), sizeof(*(stack).start))) ?                 \
        ((stack).top = (stack).start,                                           \
         (stack).end = (stack).start+(size),                                    \
         true) : false)

#define STACK_FREE(stack) \
    (free((stack).start),(stack).start = (stack).top = (stack).end = 0)

#define STACK_EMPTY(stack)  ((stack).start == (stack).top)

#define STACK_LENGTH(stack)  ((stack).top - (stack).start)

#define STACK_SIZE(stack)  ((stack).end - (stack).start)

#define STACK_LIMIT(stack,size) \
    (STACK_LENGTH(stack) < (size) ? true : false)

#define STACK_PUSH(stack,value)                                                  \
    (((stack).top != (stack).end                                                 \
      || macro_stack_extend((void **)&(stack).start,                             \
              (void **)&(stack).top, (void **)&(stack).end)) ?                   \
        (*((stack).top++) = value,                                               \
         true) : false)

#define STACK_POP(stack) (*(--(stack).top)) /* return point of data */

#define STACK_TOP(stack) (*((stack).top-1)) /* return point of data */

/*
 * Queue management
 */

#define QUEUE_ALLOC(queue,size)                                                  \
    (((queue).start = malloc((size)*sizeof(*(queue).start))) ?                   \
        ((queue).head = (queue).tail = (queue).start,                            \
         (queue).end = (queue).start+(size),                                     \
         true) : false)

#define QUEUE_FREE(queue) \
    (free((queue).start), \
     (queue).start = (queue).head = (queue).tail = (queue).end = 0)

#define QUEUE_EMPTY(queue)  ((queue).head == (queue).tail)

#define QUEUE_LENGTH(queue)  ((queue).tail - (queue).head)

#define QUEUE_SIZE(queue)  ((queue).end - (queue).start)

#define QUEUE_LIMIT(queue,size) \
    (QUEUE_LENGTH(queue) < (size) ? true : false)

#define ENQUEUE(queue,value)                                                     \
    (((queue).tail != (queue).end                                                \
      || macro_queue_extend((void **)&(queue).start, (void **)&(queue).head,     \
            (void **)&(queue).tail, (void **)&(queue).end)) ?                    \
        (*((queue).tail++) = value,                                              \
         true) : false)

#define DEQUEUE(queue)  (*((queue).head++)) /* return point of data */

#define QUEUE_INSERT(queue,index,value)                                          \
    (((queue).tail != (queue).end                                                \
      || macro_queue_extend((void **)&(queue).start, (void **)&(queue).head,     \
            (void **)&(queue).tail, (void **)&(queue).end)) ?                    \
        (memmove((queue).head+(index)+1,(queue).head+(index),                    \
            ((queue).tail-(queue).head-(index))*sizeof(*(queue).start)),         \
         *((queue).head+(index)) = value,                                        \
         (queue).tail++,                                                         \
         true) : false)

#define QUEUE_FRONT(queue) (*(queue).head) /* return point of data */

#define QUEUE_BACK(queue) (*((queue).tail-1)) /* return point of data */

#endif  // _WRD_DATA_H__
